package com.xh.bussiness.exam.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.xh.bussiness.exam.bean.dto.*;
import com.xh.bussiness.exam.bean.request.QueryStudentPaperAnswerRequest;
import com.xh.bussiness.exam.bean.request.StudentPaperAnswerRequest;
import com.xh.bussiness.exam.bean.request.SubmitEvaluationResultDto;
import com.xh.bussiness.exam.model.StudentPaperAnswer;
import com.xh.bussiness.exam.dao.StudentPaperAnswerMapper;
import com.xh.bussiness.exam.model.StudentPaperAnswerDetail;
import com.xh.bussiness.exam.service.IPaperQuestionTestDetailService;
import com.xh.bussiness.exam.service.IStudentPaperAnswerDetailService;
import com.xh.bussiness.exam.service.IStudentPaperAnswerService;
import com.xh.bussiness.practice.bean.dto.PracticeStudentResultDTO;
import com.xh.bussiness.practice.model.PracticeStudentResult;
import com.xh.bussiness.system.model.Dictionary;
import com.xh.bussiness.system.model.Student;
import com.xh.bussiness.system.service.IDictionaryService;
import com.xh.bussiness.system.service.IStudentService;
import com.xh.bussiness.tiku.bean.dto.*;
import com.xh.bussiness.tiku.bean.request.PaperQuestionRequest;
import com.xh.bussiness.tiku.model.Knowledge;
import com.xh.bussiness.tiku.model.Paper;
import com.xh.bussiness.tiku.model.PaperQuestion;
import com.xh.bussiness.tiku.model.Question;
import com.xh.bussiness.tiku.service.IKnowledgeService;
import com.xh.bussiness.tiku.service.IPaperQuestionService;
import com.xh.bussiness.tiku.service.IPaperService;
import com.xh.bussiness.tiku.service.IQuestionService;
import com.xh.bussiness.tiku.util.CheckQuestionUtil;
import com.xh.bussiness.tiku.util.QuestionConverUtils;
import com.xh.core.exception.XhException;
import com.xh.core.service.impl.BaseServiceImpl;
import com.xh.core.util.MathUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xh.core.bean.XhPage;
import com.xh.core.util.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Pitt Cheung
 * @since 2021-07-28
 */
@Service
public class StudentPaperAnswerServiceImpl extends BaseServiceImpl<StudentPaperAnswerMapper, StudentPaperAnswer> implements IStudentPaperAnswerService {

    @Autowired
    private IPaperService paperService;
    @Autowired
    private IStudentPaperAnswerDetailService studentPaperAnswerDetailService;
    @Autowired
    private IQuestionService questionService;
    @Autowired
    private IDictionaryService dictionaryService;
    @Autowired
    private IPaperQuestionService paperQuestionService;
    @Autowired
    private IKnowledgeService knowledgeService;
    @Autowired
    private IStudentService studentService;

    @Override
    public XhPage queryStudentPaperAnswerPage(XhPage page, QueryStudentPaperAnswerRequest bean) {
        return this.dao.queryStudentPaperAnswerPage(page, bean);
    }

    @Override
    public List queryStudentPaperAnswer(StudentPaperAnswerRequest bean) {
        QueryWrapper qw = new QueryWrapper<StudentPaperAnswer>();
        //拼装条件
        qw = prepareParams(bean, qw);

        return this.dao.selectList(qw);
    }

    @Override
    public void submitEvaluationResult(SubmitEvaluationResultDto request) {
        Paper paper = paperService.getById(request.getPaperId());
        if (paper == null) {
            throw new XhException("测评不存在");
        }
        QueryWrapper qw = new QueryWrapper();
        qw.eq("student_id", request.getStudentId());
        qw.eq("paper_id", request.getPaperId());
        StudentPaperAnswer studentPaperAnswer = this.selectFirst(qw);
        if (studentPaperAnswer == null) {
            studentPaperAnswer = new StudentPaperAnswer();
            studentPaperAnswer.setStudentId(request.getStudentId());
            studentPaperAnswer.setPaperId(request.getPaperId());
            studentPaperAnswer.setStatus(request.getStatus());
            this.insert(studentPaperAnswer);
        } else {
            studentPaperAnswerDetailService.deleteByAnswerIdId(studentPaperAnswer.getId());
        }
        List<StudentPaperAnswerDetail> results = new ArrayList<>();
        for (PracticeStudentResultDTO practiceStudentResult : request.getPracticeStudentResults()) {
            StudentPaperAnswerDetail detail = new StudentPaperAnswerDetail();
            detail.setStudentPaperAnswerId(studentPaperAnswer.getId());
            detail.setQuestionId(practiceStudentResult.getQuestionId());
            detail.setSubmitAnswer(practiceStudentResult.getAnswerContent().toJSONString());

            Question question = questionService.getById(practiceStudentResult.getQuestionId());
            Dictionary subject = dictionaryService.queryByCode(question.getSubjectId(), "SUBJECT");
            AnswerResultDto answerResultDto = CheckQuestionUtil.checkAnswer(question.getSubjectId() == null ? "" : subject.getName(), question.getBasicType(), question.getRightAnswer(), practiceStudentResult.getAnswerContent().toJSONString(), practiceStudentResult.getScore());
            detail.setAnswerResult(answerResultDto.getResult());
            detail.setScore(answerResultDto.getScore().intValue());

            results.add(detail);
        }
        studentPaperAnswerDetailService.batchInsert(results);

        studentPaperAnswer.setStatus(request.getStatus());
        if (request.getStatus() != null && request.getStatus() == 2) {
            studentPaperAnswer.setSubmitTime(new Date());
            paperService.updateAnswerCount(request.getPaperId());
        }
        this.update(studentPaperAnswer);
    }

    @Override
    public List<PracticeStudentResultDTO> queryStudentPaperAnswer(String studentId, String paperId) {
        QueryWrapper qw = new QueryWrapper();
        qw.eq("student_id", studentId);
        qw.eq("paper_id", paperId);
        StudentPaperAnswer studentPaperAnswer = this.selectFirst(qw);
        if (studentPaperAnswer == null) {
            return new ArrayList<>();
        }
        QueryWrapper detailQw = new QueryWrapper();
        detailQw.eq("student_paper_answer_id", studentPaperAnswer.getId());
        List<StudentPaperAnswerDetail> list = studentPaperAnswerDetailService.selectList(detailQw, StudentPaperAnswerDetail.class);
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<PracticeStudentResultDTO> dtos = new ArrayList<>();
        list.forEach(item -> {
            PracticeStudentResultDTO dto = new PracticeStudentResultDTO();
            dto.setAnswerContent(JSONArray.parseArray(item.getSubmitAnswer()));
            dto.setCorrect(item.getAnswerResult());
            dto.setQuestionId(item.getQuestionId());
            dtos.add(dto);
        });
        return dtos;
    }

    static Map<Integer, String> difficultMap = new HashMap<>();

    static {
        difficultMap.put(11, "容易");
        difficultMap.put(12, "较易");
        difficultMap.put(13, "一般");
        difficultMap.put(14, "较难");
        difficultMap.put(15, "困难");
    }

    @Override
    public StudentPaperAnalysisInfoDto queryPaperTestStudentKnowledgeAnalysisReport(String studentId, String paperId) {
        List<PracticeStudentResultDTO> dtos = queryStudentPaperAnswer(studentId, paperId);
        if (CollectionUtils.isEmpty(dtos)) {
            return null;
        }
        //获取试卷所有试题
        PaperQuestionRequest paperQuestionRequest = new PaperQuestionRequest();
        paperQuestionRequest.setPaperId(paperId);
        paperQuestionService.queryPaperQuestion(paperQuestionRequest);
        List<PaperQuestion> paperQuestions = paperQuestionService.queryPaperQuestion(paperQuestionRequest);


        Map<String, PracticeStudentResultDTO> studentQuestionMap = dtos.stream().collect(Collectors.toMap(PracticeStudentResultDTO::getQuestionId, PracticeStudentResultDTO -> PracticeStudentResultDTO));
        List<String> questionIds = dtos.stream().map(PracticeStudentResultDTO::getQuestionId).collect(Collectors.toList());

        Map<String, PaperTestStudentKnowledgeReportDto> detailMaps = new HashMap<>();
        List<QuestionDto> questionDtos = new ArrayList<>();
        for (String questionId : questionIds) {
            QuestionDto practiceQuestion = questionService.getPracticeQuestion(questionId, null, true, true, false, false, false);
            PracticeStudentResultDTO studentResultDTO = studentQuestionMap.get(questionId);
            Optional<PaperQuestion> first = paperQuestions.stream().filter(item -> item.getQuestionId().equals(questionId)).findFirst();
            if (!first.isPresent()) {
                continue;
            }
            PaperQuestion paperQuestion = first.get();

            Integer questionDifficult = practiceQuestion.getDifficult() == null ? 13 : practiceQuestion.getDifficult();
            List<Knowledge> knowledges = practiceQuestion.getKnowledges();
            //因为惠总说的要统计三层的知识点
            if (CollectionUtils.isEmpty(knowledges)) {
                continue;
            }
            for (Knowledge knowledge : knowledges) {
                long count = Arrays.stream(knowledge.getPath().split("-")).filter(StringUtils::isNotEmpty).count();
                if (count < 2) {
                    continue;
                }
                if (detailMaps.containsKey(knowledge.getId())) {
                    PaperTestStudentKnowledgeReportDto node = detailMaps.get(knowledge.getId());
                    node.setQuestionCount(node.getQuestionCount() + 1);
                    node.setPaperQuestionScore(node.getPaperQuestionScore() + (paperQuestion.getScore() == null ? 0 : paperQuestion.getScore()));
                    node.setScore(node.getScore() + (studentResultDTO.getScore() == null ? 0 : studentResultDTO.getScore()));
                    Integer difficulty = node.getDifficulty() + questionDifficult;
                    //算出平均难度
                    int avgDifficult = new Double(MathUtils.divTwoNumberRoundHalfUp(difficulty, node.getQuestionCount(), 0)).intValue();
                    String difficultName = difficultMap.get(avgDifficult);
                    node.setDifficultyName(StringUtils.isEmpty(difficultName) ? "一般" : difficultName);
                    //算出得分比
                    double v = node.getPaperQuestionScore().doubleValue();
                    if (node.getScore().equals(v)) {
                        node.setScoreRatio(100.0);
                        node.setGraspLevel("已掌握");
                    } else {
                        double v1 = MathUtils.divTwoNumberRoundHalfUp(node.getScore(), node.getPaperQuestionScore(), 1);
                        node.setScoreRatio(MathUtils.getNumberRate(v1, 1));
                        if (v1 > 0) {
                            node.setGraspLevel("部分掌握");
                        } else {
                            node.setGraspLevel("未掌握");
                        }
                    }
                } else {
                    PaperTestStudentKnowledgeReportDto node = new PaperTestStudentKnowledgeReportDto();
                    node.setKnowledgeName(knowledge.getName());
                    node.setDifficulty(questionDifficult);

                    String difficultName = difficultMap.get(questionDifficult);
                    node.setDifficultyName(StringUtils.isEmpty(difficultName) ? "一般" : difficultName);

                    node.setQuestionCount(1);
                    node.setScore(studentResultDTO.getScore() == null ? 0 : studentResultDTO.getScore());
                    node.setPaperQuestionScore(paperQuestion.getScore() == null ? 0 : paperQuestion.getScore());
                    //得分占比
                    double v = paperQuestion.getScore().doubleValue();
                    if (studentResultDTO.getScore() != null) {
                        if (studentResultDTO.getScore().equals(v) && studentResultDTO.getScore() != 0) {
                            node.setScoreRatio(100.0);
                            node.setGraspLevel("已掌握");
                        } else {
                            double v1 = MathUtils.divTwoNumberRoundHalfUp(studentResultDTO.getScore(), paperQuestion.getScore(), 1);
                            node.setScoreRatio(MathUtils.getNumberRate(v1, 1));
                            if (v1 > 0) {
                                node.setGraspLevel("部分掌握");
                            } else {
                                node.setGraspLevel("未掌握");
                            }
                        }
                    } else {
                        node.setScoreRatio(0.0);
                        node.setGraspLevel("未掌握");
                    }
                    detailMaps.put(knowledge.getId(), node);
                }
            }
            questionDtos.add(practiceQuestion);
        }

        Map<String, List<PaperTestStudentKnowledgeReportDto>> twoLevel = new HashMap<>();

        List<PaperTestStudentKnowledgeNode> twoNodeList = new ArrayList<>();
        detailMaps.forEach((k, v) -> {
            Knowledge knowledge = knowledgeService.getById(k);
            if (knowledge != null) {
                Knowledge twoNode = knowledgeService.getById(knowledge.getParentId());
                List<PaperTestStudentKnowledgeReportDto> datas;
                if (twoLevel.containsKey(twoNode.getId())) {
                    datas = twoLevel.get(twoNode.getId());
                } else {
                    datas = new ArrayList<>();

                    PaperTestStudentKnowledgeNode node = new PaperTestStudentKnowledgeNode();
                    node.setId(twoNode.getId());
                    node.setName(twoNode.getName());
                    node.setParentId(twoNode.getParentId());
                    twoNodeList.add(node);
                }
                datas.add(v);
                twoLevel.put(twoNode.getId(), datas);
            }
        });
        Map<String, PaperTestStudentKnowledgeNode> oneLevel = new HashMap<>();
        for (PaperTestStudentKnowledgeNode node : twoNodeList) {
            List<PaperTestStudentKnowledgeReportDto> datas = twoLevel.get(node.getId());
            node.setData(datas);

            Double sumScore = 0.0;
            if (!CollectionUtils.isEmpty(datas)) {
                sumScore = datas.stream().mapToDouble(PaperTestStudentKnowledgeReportDto::getScore).sum();
            }

            Knowledge oneNodeKnowledge = knowledgeService.getById(node.getParentId());
            if (oneNodeKnowledge != null) {
                if (oneLevel.containsKey(oneNodeKnowledge.getId())) {
                    PaperTestStudentKnowledgeNode node1 = oneLevel.get(oneNodeKnowledge.getId());
                    node1.getChildes().add(node);
                    node1.setScore(node1.getScore() + sumScore);

                    oneLevel.put(oneNodeKnowledge.getId(), node1);
                } else {
                    List<PaperTestStudentKnowledgeNode> childes = new ArrayList<>();
                    childes.add(node);

                    PaperTestStudentKnowledgeNode oneNode = new PaperTestStudentKnowledgeNode();
                    oneNode.setId(oneNodeKnowledge.getId());
                    oneNode.setName(oneNodeKnowledge.getName());
                    oneNode.setChildes(childes);
                    oneNode.setScore(sumScore);

                    oneLevel.put(oneNodeKnowledge.getId(), oneNode);
                }
            }
        }
        List<PaperTestStudentKnowledgeNode> oneLevelResultList = new ArrayList(oneLevel.values());
        List<StudentPaperKnowledgeScoreDto> knowledgeNodes = new ArrayList<>();
        if (!CollectionUtils.isEmpty(oneLevelResultList)) {
            Double totalSumScore = oneLevelResultList.stream().mapToDouble(PaperTestStudentKnowledgeNode::getScore).sum();
            for (PaperTestStudentKnowledgeNode node : oneLevelResultList) {
                StudentPaperKnowledgeScoreDto knowledgeScoreDto = new StudentPaperKnowledgeScoreDto();
                knowledgeScoreDto.setKnowledgeName(node.getName());
                knowledgeScoreDto.setScoreRatio(MathUtils.getNumberRate(MathUtils.divTwoNumberRoundHalfUp(totalSumScore, node.getScore().intValue(), 1), 1));
                knowledgeNodes.add(knowledgeScoreDto);
            }
        }
        StudentPaperAnalysisInfoDto dto = new StudentPaperAnalysisInfoDto();
        dto.setKnowledgeNodes(oneLevelResultList);
        dto.setKnowledgeScoreDtos(knowledgeNodes);
        dto.setKnowledgeCount(oneLevelResultList.size());

        return dto;
    }

    @Override
    public StudentPaperAnalysisInfoDto queryPaperTestStudentAnalysisInfoReport(String studentId, String paperId) {
        QueryWrapper answerWrapper = new QueryWrapper();
        answerWrapper.eq("student_id", studentId);
        answerWrapper.eq("paper_id", paperId);
        StudentPaperAnswer studentPaperAnswer = this.selectFirst(answerWrapper);
        if (studentPaperAnswer == null) {
            throw new XhException("学生作答结果不存在");
        }
        List<StudentPaperAnswerDetail> studentPaperAnswerDetails = studentPaperAnswerDetailService.queryByAnswerId(studentPaperAnswer.getId());
        if (CollectionUtils.isEmpty(studentPaperAnswerDetails)) {
            throw new XhException("学生作答结果不存在");
        }
        PaperDto paper = paperService.getPaper(studentPaperAnswer.getPaperId());

        List<QuestionDto> allQuestions = new ArrayList<>();

        //获取试卷所有试题
        PaperQuestionRequest paperQuestionRequest = new PaperQuestionRequest();
        paperQuestionRequest.setPaperId(paperId);
        paperQuestionService.queryPaperQuestion(paperQuestionRequest);
        List<PaperQuestion> paperQuestions = paperQuestionService.queryPaperQuestion(paperQuestionRequest);
        if (CollectionUtils.isEmpty(paperQuestions)) {
            throw new XhException("试卷内容为空");
        }
        StudentPaperAnalysisInfoDto resultDto = new StudentPaperAnalysisInfoDto();
        resultDto.setReportStatus(studentPaperAnswer.getReportStatus());

        StudentPaperAnalysis paperAnalysis = new StudentPaperAnalysis();
        //学生得分
        Integer studentTotalScore = studentPaperAnswerDetails.stream().filter(item->item.getScore() != null).mapToInt(StudentPaperAnswerDetail::getScore).sum();
        Integer paperTotalScore = paperQuestions.stream().filter(item -> item.getScore() != null).mapToInt(PaperQuestion::getScore).sum();

        resultDto.setStudentPaperScore(studentTotalScore);

        paperAnalysis.setSubject(dictionaryService.queryByCode(paper.getSubjectId(), "SUBJECT").getName());
        paperAnalysis.setQuestionCount(MathUtils.getCollectionSize(paperQuestions));
        paperAnalysis.setPaperScore(paperTotalScore);
        //作答正确数
        long rightCount = studentPaperAnswerDetails.stream().filter(item -> item.getAnswerResult().equals(1)).count();
        //作答错误数
        long errorCount = studentPaperAnswerDetails.stream().filter(item -> !item.getAnswerResult().equals(1)).count();
        resultDto.setRightCount(rightCount);
        resultDto.setErrorCount(errorCount);

        List<PaperQuestionDto> difficultQuestionList = null;
        if (paper.getChapterCount() != null && paper.getChapterCount() > 0) {
            for (PaperChapterDto paperChapter : paper.getPaperCharpts()) {
                difficultQuestionList = paperChapter.getQuestions().stream().filter(item -> item.getQuestion().getDifficult() != null).collect(Collectors.toList());
                allQuestions.addAll(paperChapter.getQuestions().stream().map(PaperQuestionDto::getQuestion).collect(Collectors.toList()));
            }
        } else {
            difficultQuestionList = paper.getQuestions().stream().filter(item -> item.getQuestion().getDifficult() != null).collect(Collectors.toList());
            allQuestions.addAll(paper.getQuestions().stream().map(PaperQuestionDto::getQuestion).collect(Collectors.toList()));
        }
        if (CollectionUtils.isEmpty(difficultQuestionList)) {
            paperAnalysis.setDifficult("一般");
        }else{
            int allDifficult = difficultQuestionList.stream().mapToInt(item -> item.getQuestion().getDifficult()).sum();
            int avgDifficult = new Double(MathUtils.divTwoNumberRoundHalfUp(allDifficult, difficultQuestionList.size(), 0)).intValue();
            String difficultName = difficultMap.get(avgDifficult);
            if (StringUtils.isEmpty(difficultName)) {
                paperAnalysis.setDifficult("一般");
            }else{
                paperAnalysis.setDifficult(difficultName);
            }
        }
        //难度维度统计
        List<StudentPaperQuestionDifficultDto> questionDifficultList = studentPaperAnswerDetailService.queryStudentPaperQuestionDifficult(studentPaperAnswer.getId());
        if (!CollectionUtils.isEmpty(questionDifficultList)) {
            Map<Integer, List<StudentPaperQuestionDifficultDto>> difficultQuestionMap = questionDifficultList.stream().collect(Collectors.groupingBy(StudentPaperQuestionDifficultDto::getDifficult));

            List<StudentPaperDifficultAnalysisDto> difficultAnalysisDtos = new ArrayList<>();
            difficultQuestionMap.forEach((k,v)->{
                StudentPaperDifficultAnalysisDto difficultAnalysisDto = new StudentPaperDifficultAnalysisDto();
                difficultAnalysisDto.setDifficultName(difficultMap.get(k));
                difficultAnalysisDto.setQuestionCount(MathUtils.getCollectionSize(v));
                difficultAnalysisDto.setRightQuestionCount(v.stream().filter(item->item.getAnswerResult().equals(1)).count());
                difficultAnalysisDto.setErrorQuestionCount(v.stream().filter(item -> !item.getAnswerResult().equals(1)).count());
                difficultAnalysisDto.setRightRatio(MathUtils.getNumberRate(MathUtils.divTwoNumberRoundHalfUp(difficultAnalysisDto.getRightQuestionCount(), difficultAnalysisDto.getQuestionCount(), 1), 1));
                difficultAnalysisDto.setProportion(MathUtils.getNumberRate(MathUtils.divTwoNumberRoundHalfUp(difficultAnalysisDto.getQuestionCount(),questionDifficultList.size(), 1), 1));
                difficultAnalysisDtos.add(difficultAnalysisDto);
            });
            resultDto.setDifficultAnalysisDtos(difficultAnalysisDtos);
        }
        resultDto.setPaperAnalysis(paperAnalysis);

        List<StudentPaperQuestionAnswerDto> answerDtos = new ArrayList<>();
        for (StudentPaperAnswerDetail studentPaperAnswerDetail : studentPaperAnswerDetails) {
            StudentPaperQuestionAnswerDto dto = new StudentPaperQuestionAnswerDto();
            dto.setResult(studentPaperAnswerDetail.getAnswerResult());
            dto.setStudentAnswer(StringUtils.isEmpty(studentPaperAnswerDetail.getSubmitAnswer()) ? null : (JSON)JSON.parse(studentPaperAnswerDetail.getSubmitAnswer()));
            dto.setQuestionDto(allQuestions.stream().filter(item -> item.getId().equals(studentPaperAnswerDetail.getQuestionId())).findFirst().get());

            answerDtos.add(dto);
        }
        resultDto.setStudentQuestionAnswerDtos(answerDtos);

        Student student = studentService.queryStudentById(studentId);
        if(student!=null){
            resultDto.setStudentName(student.getName());
        }
        return resultDto;
    }


    /**
     * 准备条件
     *
     * @param bean
     * @param qw
     */
    private QueryWrapper prepareParams(StudentPaperAnswerRequest bean, QueryWrapper qw) {
        if (bean.getIds() != null && bean.getIds().length > 0) {
            qw.in("id", bean.getIds());
        }
        return qw;
    }
}
